package com.wg.db.schema;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.vdurmont.emoji.EmojiParser;
import com.wg.db.exception.DataException;
import com.wg.core.utils.ZipUtils;
import com.wg.db.annotation.Emoji;
import com.wg.db.annotation.EntityField;
import com.wg.db.annotation.Zip;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * 实体映射字段信息
 * 该类用于描述数据库表字段与Java实体类属性之间的映射关系，
 * 并提供字段值的获取和设置功能，支持类型转换和注解处理
 *
 * @author 少爷123
 */
public class SchemaColumn {
    /**
     * 所属的表结构信息
     */
    private final SchemaTable schemaTable;
    /**
     * 对应的Java字段对象
     */
    private final Field field;
    /**
     * 字段的数据类型
     */
    private final FieldType type;
    /**
     * 字段名称
     */
    private final String name;
    /**
     * 是否为主键标识
     */
    private final boolean isKey;
    /**
     * 是否需要压缩处理
     */
    private final boolean isZip;
    /**
     * 压缩后是否需要Base64编码
     */
    private final boolean isBase64ByZip;
    /**
     * 是否包含Emoji表情
     */
    private final boolean isEmoji;

    /**
     * 构造方法
     *
     * @param schemaTable 表结构信息
     * @param field       Java字段对象
     * @param entityField 实体字段注解信息
     */
    public SchemaColumn(SchemaTable schemaTable, Field field, EntityField entityField) {
        this.schemaTable = Objects.requireNonNull(schemaTable, "schemaTable must not be null");
        this.field = Objects.requireNonNull(field, "field must not be null");
        this.type = FieldType.valueOf(Objects.requireNonNull(field.getType(), "field type must not be null"));
        this.name = StrUtil.isBlank(entityField.name()) ? field.getName() : entityField.name();
        this.isKey = entityField.isKey();

        Zip zip = field.getAnnotation(Zip.class);
        this.isZip = zip != null;
        this.isBase64ByZip = this.isZip && zip.isBase64();

        this.isEmoji = field.isAnnotationPresent(Emoji.class);
    }

    public SchemaTable getSchemaTable() {
        return schemaTable;
    }

    public String getName() {
        return name;
    }

    public boolean isKey() {
        return isKey;
    }

    public FieldType getType() {
        return type;
    }

    public Field getField() {
        return field;
    }

    public boolean isZip() {
        return isZip;
    }

    public boolean isBase64ByZip() {
        return isBase64ByZip;
    }

    public boolean isEmoji() {
        return isEmoji;
    }

    /**
     * 设置对象字段的值（支持类型转换和注解处理）
     *
     * @param obj        目标对象
     * @param fieldValue 要设置的值
     */
    public void setValue(Object obj, Object fieldValue) {
        Object processedValue = processSetValue(fieldValue);
        ReflectUtil.setFieldValue(obj, field, processedValue);
    }

    /**
     * 处理值的写入逻辑（类型转换、压缩/Emoji编码）
     *
     * @param fieldValue 原始值
     * @return 处理后的值
     */
    private Object processSetValue(Object fieldValue) {
        if (fieldValue == null) {
            return null;
        }

        try {
            switch (type) {
                case String:
                    String str = Convert.toStr(fieldValue);
                    if (StrUtil.isNotEmpty(str)) {
                        if (isZip) {
                            str = ZipUtils.decodeUnGzip(str, isBase64ByZip);
                        } else if (isEmoji) {
                            str = EmojiParser.parseToUnicode(str);
                        }
                    }
                    return str;
                case Long:
                    return Convert.toLong(fieldValue);
                case Integer:
                    return Convert.toInt(fieldValue);
                case Boolean:
                    return Convert.toBool(fieldValue);
                case Float:
                    return Convert.toFloat(fieldValue);
                case Double:
                    return Convert.toDouble(fieldValue);
                case Date:
                    return Convert.toDate(fieldValue);
                case Byte:
                    return Convert.toByte(fieldValue);
                case Short:
                    return Convert.toShort(fieldValue);
                case ByteArray:
                    return Convert.toByteArray(fieldValue);
                default:
                    throw new DataException("Unsupported field type: " + type);
            }
        } catch (Exception e) {
            throw new DataException("Failed to set value for field [" + name + "], type: " + type, e);
        }
    }

    /**
     * 获取对象字段的值（支持类型转换和注解处理）
     *
     * @param obj 目标对象
     * @return 字段值
     */
    public Object getValue(Object obj) {
        Object rawValue = ReflectUtil.getFieldValue(obj, field);
        return processGetValue(rawValue);
    }

    /**
     * 处理值的读取逻辑（类型转换、压缩/Emoji解码）
     *
     * @param rawValue 原始值
     * @return 处理后的值
     */
    private Object processGetValue(Object rawValue) {
        if (rawValue == null) {
            return null;
        }

        try {
            switch (type) {
                case String:
                    String value = Convert.toStr(ReflectUtil.getFieldValue(rawValue, this.field));
                    if (StrUtil.isNotEmpty(value)) {
                        if (isZip) {
                            return ZipUtils.gzipEncode(value, isBase64ByZip);
                        } else if (isEmoji) {
                            return EmojiParser.parseToAliases(value);
                        }
                    }
                    return value;
                case Long:
                case Integer:
                case Boolean:
                case Float:
                case Double:
                case Date:
                case Byte:
                case Short:
                case ByteArray:
                    return rawValue;
                default:
                    throw new DataException("Unsupported field type: " + type);
            }

        } catch (Exception e) {
            throw new DataException("Failed to get value for field [" + name + "], type: " + type, e);
        }
    }
}